#ifndef PLAYER_H
#define PLAYER_H

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>
}
#include <queue>

//版本号
#define VERSION "2.0v\n"
//单帧最大数据
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
//包队列大小
#define PACKET_QUEUE_MAX_SIZE   8
//帧队列大小
#define FRAME_QUEUE_MAX_SIZE    16
//命名空间
namespace player
{
//音频播放控制
typedef struct AUDIOBUFCTRL
{
    //音频播放数据缓冲首地址
    unsigned char *pAudioChunk;
    //音频当前播放数据首指针
    unsigned char *pAudioPos;
    //音频当前播放剩余数据
    unsigned int audioLen;
}AudioBufCtrl;
//音频转换输出格式
typedef struct AUDIOOUTFMT
{  
    //单通道采样数据
    int outNbSamples;
    //采样率
    int outSamplesRate;
    //输出通道
    int outChannels;
    //输出帧大小
    int outFrameSize;
    //输出音频通道格式
    unsigned long outChLayout;
    //采样格式
    AVSampleFormat outNbSampleFmt;
}AudioOutFmt;
//视频转换输出格式
typedef struct VIDEOOUTFMT
{
    //存储转换后的单帧
    AVFrame *pOutFrame;
}VideoOutFmt;
//包队列相关
typedef struct PACKETQUEUE
{
    //包队列，使用C++队列模板，非线程安全
    std::queue<AVPacket *> qPacket;
    //互斥量
    SDL_mutex *pMutex;
    //条件变量
    SDL_cond *pCond;
}PacketQueue;
//帧队列相关
typedef struct FRAMEQUEUE
{
    //帧队列使用数组指针，初始化时申请所有内存，而非使用时申请
    AVFrame *qFrame[FRAME_QUEUE_MAX_SIZE];
    //队列存储最大值
    int maxSize;
    //队列当前存有元素个数
    int qSize;
    //读下标
    int readPrt;
    //写下标
    int writePrt;
    //互斥量
    SDL_mutex *pMutex;
    //条件变量
    SDL_cond *pCond;
}FrameQueue;
//编解码器相关
typedef struct CODEC
{
    //编解码器上下文
    AVCodecContext *pCodeCtx;
    //解码器
	const AVCodec *pAvCodec;
    //临时存储单帧
    AVFrame	*pFrame;
    //视频转码器
    struct SwsContext *pSwsConvertCtx;
    //音频转码器
    struct SwrContext *pSwrConvertCtx;
    //转换结果缓存
    unsigned char *pBuffer;
    //音频转换格式相关
    AudioOutFmt *pAudioOutFmt;
    //音频播放相关
    AudioBufCtrl audioBufCtrl;
    //视频转换格式相关
    VideoOutFmt videoOutFmt;
    //帧队列
    FrameQueue *pFrameQueue;
}Codec;
//所有线程退出状态
typedef union CLOSE
{
    //单个状态
    struct CLOSESINGLE
    {
        //解包线程结束状态
        unsigned char readPacketOver:1;
        //解码线程结束状态
        unsigned char decodeOver:1;
        //音频线程结束状态
        unsigned char audioOver:1;
        //视频线程结束状态
        unsigned char videoOver:1;       
    }closeSingle;
    //总状态
    unsigned char allOver;
}Close;
//播放器类
class Player
{
public:
    //输入文件名称
    char *filename;
    //事件线程是否已经退出
    bool isEventClose;
    //格式化上下文
    AVFormatContext	*pFormatCtx;
    //单包临时存储
    AVPacket *pPacket;
    //解码器数组
    Codec *pCodec;
    //构造函数
    Player(const char *file);
    //析构函数
    ~Player();
    //打印版本
    int versionShow(void);
    //初始化
    int init(void);
    //释放初始化资源
    int exit(void);
    //事件循环
    static int eventLoop(void *pthis);
    //解包循环
    static int readPackLoop(void *pthis);
    //解码循环
    static int decodeLoop(void *pthis);
    //音频循环
    static int audioLoop(void *pthis);
    //视频循环
    static int videoLoop(void *pthis);
    //音频播放回调
    static void audioCallBack(void *pthis,unsigned char *stream,int len);
    //解码器初始化
    int codecContextInit(int streamIndex);
    //解码器资源释放
    int codecContextExit(int streamIndex);
private:
    //关闭解包线程指示
    bool isReadPackClose;
    //关闭解码线程指示
    bool isDecodeClose;
    //关闭音频播放线程指示
    bool isAudioClose;
    //关闭视频播放线程指示
    bool isVideoClose;
    //线程退出状态
    Close closeOver;
    //窗口宽度
    int screenW;
    //窗口高度
    int screenH;
    //音频流索引
    int audioStreamIndex;
    //视频流索引
    int videoStreamIndex;
    //获取音频帧状态
    int gotAudioPicture;
    //获取视频帧状态
    int gotVideoPicture;
    //互斥量
    SDL_mutex *pMutex;
    //各线程索引
    SDL_Thread *eventThread;
    SDL_Thread *readPackThread;
    SDL_Thread *decodeThread;
    SDL_Thread *audioPlayerThread;
    SDL_Thread *videoPlayerThread;
    //包队列
    PacketQueue packetQueue;
    //处理键盘事件
    int keyEvent(int key);
};    
} 


#endif



